package com.suemi.missile.client;

import com.alibaba.fastjson.JSONObject;
import com.suemi.missile.common.utils.Constants;
import org.apache.commons.lang3.tuple.Pair;
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/*
 * ElasticSearch 索引管理器
 * @author suemi
 */
public class IndexManager {
  private Client client = null;

  public IndexManager(String host, int port, String cluster) throws UnknownHostException {
    connect(host, port,cluster);
  }

  public IndexManager(String host,int port) throws UnknownHostException {
    this(host,port, Constants.ES_CLUSTER);
  }

  IndexManager(Client client) {
    this.client = client;
  }

  public void connect(String host, int port,String cluster) throws UnknownHostException {
    if (client != null) client.close();
    Settings settings = Settings.builder().put("cluster.name", cluster).build();
    client = new PreBuiltTransportClient(settings)
            .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), port));
  }

  public void close() {
    client.close();
  }

  public boolean exists(String indexName) {
    return client.admin().indices().prepareExists(indexName).execute().actionGet().isExists();
  }

  public boolean exists(String indexName, String indexType) {
    return client.admin().indices().prepareTypesExists(indexName).setTypes(indexType).execute().actionGet().isExists();
  }

  public List<String> indexNames() {
    ClusterStateResponse response = client.admin().cluster()
            .prepareState()
            .execute().actionGet();

    return Arrays.asList(response.getState().getMetaData().getConcreteAllIndices());
  }

  public List<String> indexTypes(String indexName) {
    ClusterStateResponse response = client.admin().cluster().prepareState().execute().actionGet();
    ImmutableOpenMap<String, MappingMetaData> mappings = response.getState().getMetaData().index(indexName).getMappings();
    List<String> res = new ArrayList<>();
    mappings.forEach(item -> {
      res.add(item.key);
    });
    return res;
  }

  public IndexMetaData index(String indexName) {
    ClusterStateResponse response = client.admin().cluster().prepareState().execute().actionGet();
    return response.getState().getMetaData().index(indexName);
  }

  public MappingMetaData indexMapping(String indexName, String indexType) {
    ClusterStateResponse response = client.admin().cluster().prepareState().execute().actionGet();
    ImmutableOpenMap<String, MappingMetaData> mappings = response.getState().getMetaData().index(indexName).getMappings();
    return mappings.getOrDefault(indexType, null);
  }

  public void deleteIndex(String indexName) {
    client.admin().indices().prepareDelete(indexName).execute().actionGet();
  }

  public void createIndex(String indexName, JSONObject setting) {
    client.admin().indices().prepareCreate(indexName)
            .setSettings(setting.toJSONString(), XContentType.JSON)
            .execute().actionGet();
  }

  public void createIndex(String indexName, String indexType, JSONObject setting, JSONObject mapping) {
    client.admin().indices().prepareCreate(indexName)
            .setSettings(setting.toJSONString(), XContentType.JSON)
            .addMapping(indexType, mapping.toJSONString(), XContentType.JSON)
            .execute().actionGet();
  }

  public void createIndex(String indexName, JSONObject setting, Pair<String, JSONObject>... mappings) {
    CreateIndexRequestBuilder req = client.admin().indices().prepareCreate(indexName);
    req.setSettings(setting.toJSONString(), XContentType.JSON);
    for (Pair<String, JSONObject> mapping : mappings)
      req.addMapping(mapping.getLeft(), mapping.getRight().toJSONString(), XContentType.JSON);
    req.execute().actionGet();
  }

  public void putMapping(String indexName, String indexType, JSONObject mapping) {
    client.admin().indices().preparePutMapping(indexName)
            .setType(indexType).setSource(mapping.toJSONString(), XContentType.JSON)
            .execute().actionGet();
  }

  public void refresh(String... indexName) {
    client.admin().indices().prepareRefresh(indexName).execute().actionGet();
  }

}
